<script setup lang="ts">
import { computed, ref } from 'vue';

import { FormCreateItem } from '@/types/form-create';
import { NForm } from 'naive-ui';
import { FormInst, FormRules } from 'naive-ui';

import { QFormCreateProps } from './type';

const props = withDefaults(defineProps<QFormCreateProps>(), {
	items: () => [],
	inline: true,
	showReset: true,
});

const formRef = ref<FormInst | null>(null);

const formData = ref<Record<string, any>>(props.initialValues ?? {});

const rules = computed<FormRules>(() => {
	return props.items.reduce((acc, item) => {
		if (item.field && item.validate) {
			acc[item.field] = item.validate;

			item.control?.forEach((control) => {
				if (control.handle(formData.value, formRef.value)) {
					control.items.forEach((item) => {
						if (item.field && item.validate) {
							acc[item.field] = item.validate;
						}
					});
				}
			});
		}
		return acc;
	}, {} as FormRules);
});

const formItems = computed(() => {
	const data = props.items.reduce((acc, item) => {
		acc.push(item);
		acc.push(...(item.control?.filter((control) => control.handle(formData.value, formRef.value))?.flatMap((control) => control.items) ?? []));
		return acc;
	}, [] as FormCreateItem[]);

	return data;
});

const reset = () => {
	formData.value = props.initialValues ? { ...props.initialValues } : {};
};

const setValues = (values: Record<string, any>, type: 'cover' | 'merge' = 'cover') => {
	if (type === 'cover') {
		formData.value = values;
	} else {
		formData.value = { ...formData.value, ...values };
	}
};

const getValues = () => {
	return formData.value;
};

const validate = (callback: (error: boolean) => void) => {
	formRef.value?.validate((error) => {
		callback(!!error);
	});
};

const hasPermission = (permission: string) => {
	return uni.$hasPermission(permission);
};

// 暴露方法
defineExpose({
	formRef,
	setValues,
	reset,
	validate,
	getValues,
});
</script>

<template>
	<n-form class="" ref="formRef" require-mark-placement="left" label-placement="left" :label-width="labelWidth" :rules="rules" :model="formData">
		<template v-for="item in formItems" :key="item.field">
			<n-form-item v-if="item.permission ? hasPermission(item.permission) : true" :label="item.title" :path="item.field" v-bind="item.wrap">
				<template #label>
					<div class="flex items-center">
						<span>
							{{ item.title }}
						</span>
						<n-tooltip trigger="hover" v-if="item.info">
							<template #trigger>
								<i class="icon-[ant-design--question-circle-outlined] cursor-help"></i>
							</template>
							{{ item.info }}
						</n-tooltip>
					</div>
				</template>
				<form-item-map :item="item" :form-data="formData">
					<template v-for="(slot, name) in $slots" #[name]="scope">
						<slot :name="name" v-bind="{ ...scope, formData, formRef }" />
					</template>
				</form-item-map>
			</n-form-item>
		</template>
	</n-form>
</template>

<style scoped></style>
